﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PoserLoot.Web.Models.Validation;
using System.Collections.Specialized;
using System.Reflection;
using System.Text;
using System.IO;
using System.Xml.Serialization;


namespace PoserLoot.Web.Models
{
    public class Service : IService
    {
        private IValidationDictionary _validationDictionary;
        private IRepository _repository;

        public Service(IValidationDictionary validationDictionary)
            : this(validationDictionary, new EntityRepository())
        { }

        public Service(IValidationDictionary validationDictionary, IRepository repository)
        {
            _validationDictionary = validationDictionary;
            _repository = repository;
        }

        #region Category methods

        public bool ValidateCategory(Category category)
        {
            if (String.IsNullOrEmpty(category.Appellation))
                _validationDictionary.AddError("Appellation", "Cannot be null or empty.");

            return _validationDictionary.IsValid;
        }

        public bool CreateCategory(Category category)
        {
            // Validation logic
            if (!ValidateCategory(category))
                return false;

            // Database logic
            try
            {
                category.CategoryId = Guid.NewGuid();
                _repository.CreateCategory(category);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool DeleteCategory(Guid categoryId)
        {
            var category = this.GetCategory(categoryId);

            // Validation logic
            if (!ValidateCategory(category))
                return false;

            try
            {
                _repository.DeleteCategory(category);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool EditCategory(Category category)
        {
            // Validation logic
            if (!ValidateCategory(category))
                return false;

            // Database logic
            try
            {
                _repository.EditCategory(category);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public Category GetCategory(Guid categoryId)
        {
            return _repository.GetCategory(categoryId);
        }

        public IEnumerable<Category> ListCategories()
        {
            return _repository.ListCategories();
        }

        #endregion

        #region Entry methods

        public bool ValidateEntry(Entry entry)
        {
            return _validationDictionary.IsValid;
        }

        public bool CreateEntry(Entry entry)
        {
            // Validation logic
            if (!ValidateEntry(entry))
                return false;

            // Database logic
            try
            {
                entry.EntryId = Guid.NewGuid();
                entry.CreateDate = DateTime.Now;
                _repository.CreateEntry(entry);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool DeleteEntry(Guid entryId)
        {
            var entry = this.GetEntry(entryId);

            // Validation logic
            if (!ValidateEntry(entry))
                return false;

            try
            {
                _repository.DeleteEntry(entry);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool EditEntry(Entry entry)
        {
            // Validation logic
            if (!ValidateEntry(entry))
                return false;

            // Database logic
            try
            {
                _repository.EditEntry(entry);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public Entry GetEntry(Guid entryId)
        {
            return _repository.GetEntry(entryId);
        }

        public IEnumerable<Entry> ListEntries(Guid? categoryId)
        {
            return _repository.ListEntries(categoryId);
        }

        public IEnumerable<Entry> ListEntries(string keyword)
        {
            return _repository.ListEntries(keyword);
        }

        #endregion

        #region File methods

        public bool ValidateFile(File file)
        {
            return _validationDictionary.IsValid;
        }

        public bool CreateFile(File file)
        {
            // Validation logic
            if (!ValidateFile(file))
                return false;

            try
            {
                file.FileId = Guid.NewGuid();
                _repository.CreateFile(file);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;            
        }

        public bool DeleteFile(Guid fileId)
        {
            var file = this.GetFile(fileId);

            // Validation logic
            if (!ValidateFile(file))
                return false;

            try
            {
                _repository.DeleteFile(file);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool EditFile(File file)
        {
            throw new NotImplementedException();
        }

        public File GetFile(Guid fileId)
        {
            return _repository.GetFile(fileId);
        }

        public IEnumerable<File> ListFiles(Guid entryId)
        {
            return _repository.ListFiles(entryId);
        }

        #endregion

        #region Gallery methods

        public bool ValidateGallery(Gallery gallery)
        {
            return _validationDictionary.IsValid;
        }

        public bool CreateGallery(Gallery gallery)
        {
            // Validation logic
            if (!ValidateGallery(gallery))
                return false;

            try
            {
                gallery.GalleryId = Guid.NewGuid();
                gallery.Path = System.IO.Path.Combine(gallery.Path, gallery.GalleryId.ToString("B") + ".jpg");

                TimeSpan elapsedSpan = DateTime.Now.Subtract(new DateTime(2009, 1, 1));
                gallery.OrderIndex = (int)elapsedSpan.TotalSeconds;

                using (System.Net.WebClient wc = new System.Net.WebClient())
                {
                    wc.DownloadFile(gallery.ReferenceUrl, gallery.Path);
                }

                _repository.CreateGallery(gallery);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool DeleteGallery(Guid galleryId)
        {
            var gallery = this.GetGallery(galleryId);

            // Validation logic
            if (!ValidateGallery(gallery))
                return false;

            try
            {
                gallery.EntryReference.Load();
                if (gallery.Entry.Thumbnail == gallery)
                    gallery.Entry.Thumbnail = null;

                System.IO.File.Delete(gallery.Path);
                _repository.DeleteGallery(gallery);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool EditGallery(Gallery gallery)
        {
            throw new NotImplementedException();
        }

        public Gallery GetGallery(Guid galleryId)
        {
            return _repository.GetGallery(galleryId);
        }

        public IEnumerable<Gallery> ListGallerys(Guid entryId)
        {
            return _repository.ListGallerys(entryId);
        }

        public Stream GetGalleryOriginalStream(Guid galleryId)
        {

            Gallery gallery = this.GetGallery(galleryId);
            string path = HttpContext.Current.Server.MapPath("~/App_Data/Gallery/" + gallery.GalleryId.ToString("B") + ".jpg");
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete);

            return fs;
        }

        public Stream GetGalleryThumbnailStream(Guid galleryId)
        {
            Gallery gallery = this.GetGallery(galleryId);
            string path = HttpContext.Current.Server.MapPath("~/App_Data/Gallery/" + gallery.GalleryId.ToString("B") + ".jpg");
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Delete))
            {
                System.Drawing.Image originalImage = System.Drawing.Image.FromStream(fs);

                int towidth = 125;
                int toheight = 100;

                int x = 0;
                int y = 0;
                int ow = originalImage.Width;
                int oh = originalImage.Height;

                if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
                {
                    oh = originalImage.Height;
                    ow = originalImage.Height * towidth / toheight;
                    y = 0;
                    x = (originalImage.Width - ow) / 2;
                }
                else
                {
                    ow = originalImage.Width;
                    oh = originalImage.Width * toheight / towidth;
                    x = 0;
                    y = (originalImage.Height - oh) / 2;
                }

                System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);
                System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.Clear(System.Drawing.Color.Transparent);
                g.DrawImage(originalImage, new System.Drawing.Rectangle(0, 0, towidth, toheight),
                    new System.Drawing.Rectangle(x, y, ow, oh),
                    System.Drawing.GraphicsUnit.Pixel);

                MemoryStream ms = new MemoryStream();
                bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                ms.Position = 0;

                return ms;
            }
        }

        #endregion

        #region Comment methods

        public bool ValidateComment(Comment comment)
        {
            return _validationDictionary.IsValid;
        }

        public bool CreateComment(Comment comment)
        {
            // Validation logic
            if (!ValidateComment(comment))
                return false;

            try
            {
                comment.CommentId = Guid.NewGuid();
                comment.CreateDate = DateTime.Now;
                _repository.CreateComment(comment);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool DeleteComment(Guid commentId)
        {
            var comment = this.GetComment(commentId);

            // Validation logic
            if (!ValidateComment(comment))
                return false;

            try
            {
                _repository.DeleteComment(comment);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public bool EditComment(Comment comment)
        {
            // Validation logic
            if (!ValidateComment(comment))
                return false;

            try
            {
                _repository.EditComment(comment);
            }
            catch (Exception ex)
            {
                _validationDictionary.AddError("Exception", ex.ToString());
                return false;
            }
            return true;
        }

        public Comment GetComment(Guid commentId)
        {
            return _repository.GetComment(commentId);
        }

        public IEnumerable<Comment> ListComments(Guid entryId)
        {
            return _repository.ListComments(entryId);
        }

        #endregion
    }
}
